package control;

import java.util.Vector;

import storage.ManageData;
import utils.CommandAnalyzer;

import basic.CRUDable;
import basic.Manager;
import domain.FamilyMember;

//@author A0098891H
public class MemberManager extends Manager{
	
	private Vector<FamilyMember> _listOfMember;
	
	/**
	 * @param o
	 */
	public MemberManager(Object o)
	{
		this.initialize();
	}

	/**
	 * 
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public Vector<FamilyMember> getList()
	{
		return _listOfMember;
	}
	/**
	 *
	 * @see basic.Manager#add(basic.CRUDable)
	 * @param member
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public int add(CRUDable member) {
		//check uniqueness
		for(FamilyMember m:_listOfMember)
		{
			if(m.isSame(((FamilyMember)member)))
				return -1;
		}
		member.set_id(_nextId++);
		this._listOfMember.add(((FamilyMember)member));
		return member.get_id();
	}
	/**
	 *
	 * @see basic.Manager#addTo(basic.CRUDable, int, int)
	 * @param member
	 * @param id
	 * @param pos
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean addTo(CRUDable member, int id,int pos) {
		//check uniqueness
		for(FamilyMember m:_listOfMember)
		{
			if(m.isSame(((FamilyMember)member)))
				return false;
		}
		member.set_id(id);
		this._listOfMember.add(pos,((FamilyMember)member));
		return true;
	}

	/**
	 *
	 * @see basic.Manager#get(int)
	 * @param id
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public FamilyMember get(int id) {
		for(FamilyMember m: _listOfMember)
		{
			if(m.get_id()==id)
				return m;
		}
		return _listOfMember.get(0);
	}

	/**
	 *
	 * @see basic.Manager#edit(int, basic.CRUDable)
	 * @param id
	 * @param member
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public FamilyMember edit(int id, CRUDable member) {
		for(FamilyMember m:_listOfMember)
		{
			if(m.isSame(((FamilyMember)member)) && m.get_id()!=id)
				return null;
		}
		for(FamilyMember m: _listOfMember)
		{
			if(m.get_id()==id)
			{
				FamilyMember mem = new FamilyMember(m);
				m.set(((FamilyMember)member));
				return mem;
			}
		}
		return null;
	}

	/**
	 *
	 * @see basic.Manager#delete(int)
	 * @param id
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public FamilyMember delete(int id) { 
		if(id==0)
			return null;
		for(FamilyMember m:_listOfMember)
		{
			if(m.get_id()==id)
			{
				if(_listOfMember.remove(m))
					return m;
				else
					return null;
			}
		}
		return null;
	}

	public int deleteFrom(int id) { 
		if(id==0)
			return -1;
		int i=0;
		for(FamilyMember m:_listOfMember)
		{
			if(m.get_id()==id)
			{
				if(_listOfMember.remove(m))
					return i;
				else
					return -1;
			}
			i++;
		}
		return -1;
	}
	/**
	 *
	 * @see interfaces.CommandLine#readCmd(java.lang.String)
	 * @param cmd
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public int readCmd(String cmd) {
		//<MEMBER>|<ADD> <NAME> (COMPULSORY)
		//<MEMBER>|<EDIT> <ID> <NAME> (COMPULSORY) 
		//OPTIONAL BUT NEED PARAMETER mn:<MIDDLENAME> bd:<BIRTHDATE> cm:<DESCRIPTION>
		
		//<MEMBER>|<DELETE> <ID>
		//<MEMBER>|<VIEW> <ID>
		//<MEMBER>|<UNDO>
		//check undo
		boolean isUndo = false;
		boolean isRedo = false;
		if(cmd.trim().compareToIgnoreCase("undo")==0)
		{
			if(!_undoStack.isEmpty())
			{
				isUndo = true;
				cmd = _undoStack.pop();
				int iAction = cmd.indexOf('[');
				int isavedId = cmd.indexOf('&');
				int isavedPos = cmd.indexOf(']');
				_undoAction = Integer.parseInt(cmd.substring(0, iAction));
				_savedId = Integer.parseInt(cmd.substring(iAction+1, isavedId));
				_savedPos = Integer.parseInt(cmd.substring(isavedId+1, isavedPos));
				
				if(_undoAction==ACTION_DELETE || _undoAction==ACTION_EDIT)
				{
					_redoStack.add(cmd.substring(0,cmd.indexOf('|')));
					cmd = cmd.substring(cmd.indexOf('|')+1);
				}
			}
		}
		else if(cmd.trim().compareToIgnoreCase("redo")==0)
		{
			if(!_redoStack.isEmpty())
			{
				isRedo = true;
				cmd = _redoStack.pop();
				if(cmd.indexOf(']')!=-1)
				{
					int iAction = cmd.indexOf('[');
					int isavedId = cmd.indexOf('&');
					int isavedPos = cmd.indexOf(']');
					_undoAction = Integer.parseInt(cmd.substring(0, iAction));
					_savedId = Integer.parseInt(cmd.substring(iAction+1, isavedId));
					_savedPos = Integer.parseInt(cmd.substring(isavedId+1, isavedPos));
					cmd = cmd.substring(cmd.indexOf(']')+1);
				}
			}	
		}
		
		String str[] = cmd.split(",");
		for(int i=0;i<str.length;i++)
		{
			str[i] = str[i].trim();
		}
		int length = str.length;
		if(length < 2)
			return -1;

		switch(str[1].toLowerCase())
		{
		case "add":
			if(length < 3) 
				return -1;
			FamilyMember member = new FamilyMember();
			member.set_name(str[2]);
			member.set_gender(CommandAnalyzer.getGender(str));
			member.set_birthDate(CommandAnalyzer.getBirthDate(str));
			member.set_description(CommandAnalyzer.getComments(str));

			_returnedObject = member;
			if(isUndo && _undoAction==ACTION_ADD)
			{
				int _savedPos = deleteFrom(_savedId);
				if(_savedPos >= 0)
				{//must record the position and id for redo
					_redoStack.add(-1+"["+_savedId+"&"+_savedPos+"]"+cmd);
					return _undoAction;
				}
				else
					return -1;//undo failed
			}
			if(isUndo && _undoAction==ACTION_DELETE)
			{
				if(!addTo(member,_savedId,_savedPos))
					return -1;
				return _undoAction;
			}

			if(isRedo)
			{
				if(!addTo(member,_savedId,_savedPos))
					return -1;
			}
			else
			{
				_savedId = add(member);
			}
			if(_savedId<0)
				return -1;
			_action = ACTION_ADD;
			
			break;
		case "delete":
			if(length < 3)
				return -1;
			_savedId = Integer.parseInt(str[2]);
			FamilyMember deletedMember = get(_savedId);
			if(deletedMember==null)
				return -1;
			_savedPos = this._listOfMember.indexOf(deletedMember);
			deletedMember = (FamilyMember) delete(_savedId);
			if(deletedMember==null)
				return -1;
			_returnedObject = deletedMember;
			cmd+="|member,add,"+deletedMember.writeToString();
			_action = ACTION_DELETE;
			
			break;
		case "edit":
			if(length < 4)
				return -1;
			_savedId = Integer.parseInt(str[2]);
			FamilyMember updatedMember = new FamilyMember();
			updatedMember.set_name(str[3]);
			updatedMember.set_gender(CommandAnalyzer.getGender(str));
			updatedMember.set_birthDate(CommandAnalyzer.getBirthDate(str));
			updatedMember.set_description(CommandAnalyzer.getComments(str));
			
			FamilyMember obsoleteMember = (FamilyMember) edit(_savedId,updatedMember);

			if(obsoleteMember==null)
				return -1;

			_returnedObject = obsoleteMember;
			if(isUndo && _undoAction==ACTION_EDIT)
			{
				return _undoAction;
			}
			cmd+="|member,edit,"+_savedId+","+obsoleteMember.writeToString();
			_action = ACTION_EDIT;
			break;
		default:
			return -1;
		}

		_undoStack.add(_action+"["+ _savedId +"&"+ _savedPos +"]"+cmd);
		
		return _action;
	}

	/**
	 *
	 * @see basic.Manager#initialize()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean initialize() {
		if(loadAll()==false)
		{
			super.initialize();
			this._listOfMember = new Vector<FamilyMember>();	
			FamilyMember defaultMember = new FamilyMember();
			defaultMember.set_name("Household");
			add(defaultMember);
		}
		return true;
	}
	
	/**
	 * 
	 * @param memManager
	 * @Precondition 
	 * @Postcondition 
	 */
	public void set(MemberManager memManager)
	{
		super.set(memManager);
		this._listOfMember = memManager._listOfMember;
	}

	/**
	 *
	 * @see basic.Manager#saveAll()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean saveAll() {
		return ManageData.saveMemberManagerToFile(this);
	}

	/**
	 *
	 * @see basic.Manager#loadAll()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	@Override
	public boolean loadAll() {
		MemberManager memManager = ManageData.loadMemberManagerFromFile();
		if(memManager==null)
		{
			return false;
		}
		this.set(memManager);
		return true;
	}

	/**
	 *
	 * @see java.lang.Object#toString()
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public String toString()
	{
		StringBuilder sb = new StringBuilder();
		for(FamilyMember member : this._listOfMember)
		{
			sb.append("  ("+member.get_id()+") "+member.toString() + "\n");
		}
		return sb.toString();
	}
	
	// Create functio to return id from input string name
	// To be used in InvestmentPlanPanel
	public int get_idFromName(String name) {
		for(FamilyMember m: _listOfMember)
		{
			if(m.get_name()==name)
				return m.get_id();
		}
		return -1;
	}
	
	/**
	 * 
	 * @return
	 * @Precondition 
	 * @Postcondition 
	 */
	public int getNumOfMember()
	{
		return _listOfMember.size();
	}
}